home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / mime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-13  |  9.9 KB  |  348 lines

  1. /*******************************************************************************
  2.  *  The Elm Mail System  -  $Revision: 5.10 $   $State: Exp $
  3.  *
  4.  *            Copyright (c) 1988-1992 USENET Community Trust
  5.  *            Copyright (c) 1986,1987 Dave Taylor
  6.  *******************************************************************************
  7.  * Bug reports, patches, comments, suggestions should be sent to:
  8.  *
  9.  *    Syd Weinstein, Elm Coordinator
  10.  *    elm@DSI.COM            dsinc!elm
  11.  *
  12.  ******************************************************************************
  13.  * $Log: mime.c,v $
  14.  * Revision 5.10  1993/05/14  03:56:19  syd
  15.  * A MIME body-part must end with a newline even when there was no newline
  16.  * at the end of the actual body or the body is null. Otherwise the next
  17.  * mime boundary may not be recognized.  The same goes with the closing
  18.  * boundary too.
  19.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  20.  *
  21.  * Revision 5.9  1993/05/08  20:25:33  syd
  22.  * Add sleepmsg to control transient message delays
  23.  * From: Syd
  24.  *
  25.  * Revision 5.8  1992/12/11  01:45:04  syd
  26.  * remove sys/types.h include, it is now included by defs.h
  27.  * and this routine includes defs.h or indirectly includes defs.h
  28.  * From: Syd
  29.  *
  30.  * Revision 5.7  1992/11/26  00:46:13  syd
  31.  * changes to first change screen back (Raw off) and then issue final
  32.  * error message.
  33.  * From: Syd
  34.  *
  35.  * Revision 5.6  1992/11/22  01:22:48  syd
  36.  * According to the MIME BNF, quoted strings are allowed in the value portion
  37.  * of a parameter.
  38.  * From: chk@alias.com (C. Harald Koch)
  39.  *
  40.  * Revision 5.5  1992/11/07  16:21:56  syd
  41.  * There is no need to write out the MIME-Version header in subparts
  42.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  43.  *
  44.  * Revision 5.4  1992/10/30  21:10:39  syd
  45.  * it invokes metamail (the pseudo is because "text" isn't a legal Content-Type).
  46.  * in src/mime.c notplain() tries to check for text but fails because it should
  47.  * look for "text\n" not "text".
  48.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  49.  *
  50.  * Revision 5.3  1992/10/25  01:47:45  syd
  51.  * fixed a bug were elm didn't call metamail on messages with a characterset,
  52.  * which could be displayed by elm itself, but message is encoded with QP
  53.  * or BASE64
  54.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  55.  *
  56.  * Revision 5.2  1992/10/24  13:44:41  syd
  57.  * There is now an additional elmrc option "displaycharset", which
  58.  * sets the charset supported on your terminal. This is to prevent
  59.  * elm from calling out to metamail too often.
  60.  * Plus a slight documentation update for MIME composition (added examples)
  61.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  62.  *
  63.  * Revision 5.1  1992/10/03  22:58:40  syd
  64.  * Initial checkin as of 2.4 Release at PL0
  65.  *
  66.  *
  67.  ******************************************************************************/
  68.  
  69.  
  70. #include "headers.h"
  71. #include "s_elm.h"
  72.  
  73. #ifdef MIME
  74.  
  75. #include <errno.h>
  76. #include <ctype.h>
  77. #include <sys/stat.h>
  78.  
  79. int check_for_multipart(filedesc)
  80. FILE *filedesc;
  81. {
  82.   char buffer[SLEN];
  83.   int Multi_Part = FALSE;
  84.   char *ptr;
  85.   char *incptr;
  86.   char Include_Filename[SLEN];
  87.   char Expanded_Filename[SLEN];
  88.  
  89.   while (mail_gets(buffer, SLEN, filedesc))
  90.     if (buffer[0] == '[') {
  91.       if (strncmp(buffer, MIME_INCLUDE, strlen(MIME_INCLUDE)) == 0) {
  92.           Multi_Part = TRUE;
  93.     if (Include_Part((FILE *)NULL, buffer, TRUE) == -1) {
  94.        return(-1);
  95.     }
  96.       }
  97.     }
  98.     rewind(filedesc);
  99.   return(Multi_Part);
  100. }
  101.  
  102. Include_Part(dest, buffer, check)
  103. FILE *dest;
  104. char *buffer;
  105. int    check;
  106. {
  107.   char *ptr;
  108.   char *incptr;
  109.   char Include_Filename[SLEN];
  110.   char Expanded_Filename[SLEN];
  111.   char tmp_fn[SLEN];
  112.   char *filename;
  113.   char Content_Type[SLEN];
  114.   char Encoding[SLEN];
  115.   char sh_buffer[SLEN];
  116.   char Encode_Flag[3];
  117.   int  Enc_Type;
  118.   FILE *incfile;
  119.   struct stat    file_status;
  120.   int  line_len;
  121.  
  122.   ptr = buffer + strlen(MIME_INCLUDE);
  123.   while ((*ptr != '\0') && (*ptr == ' '))
  124.     ptr++;
  125.   incptr = Include_Filename;
  126.   while ((*ptr != ' ') && (*ptr != ']') && (*ptr != '\0'))
  127.     *incptr++ = *ptr++;
  128.   *incptr = '\0';
  129.  
  130.   while ((*ptr != '\0') && (*ptr == ' '))
  131.     ptr++;
  132.   incptr = Content_Type;
  133.   while ((*ptr != ' ') && (*ptr != ']') && (*ptr != '\0'))
  134.     *incptr++ = *ptr++;
  135.   *incptr = '\0';
  136.  
  137.   while ((*ptr != '\0') && (*ptr == ' '))
  138.     ptr++;
  139.   incptr = Encoding;
  140.   while ((*ptr != ' ') && (*ptr != ']') && (*ptr != '\0'))
  141.     *incptr++ = *ptr++;
  142.   *incptr = '\0';
  143.  
  144.   if (strlen(Include_Filename) == 0) {
  145.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmNoIncludeFilename,
  146.                     "\n\rNo Filename given, include line ignored\n\r"), 0);
  147.     if (sleepmsg > 0)
  148.         sleep(sleepmsg);
  149.     return(-1);
  150.   }
  151.   expand_env(Expanded_Filename, Include_Filename);
  152.  
  153.   if (strlen(Content_Type) == 0) {
  154.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmNoContentTypeGiven,
  155.                     "\n\rNo Content-type given, include line ignored\n\r"), 0);
  156.     if (sleepmsg > 0)
  157.         sleep(sleepmsg);
  158.     return(-1);
  159.   }
  160.  
  161.   Enc_Type = check_encoding(Encoding);
  162.  
  163.   if (Enc_Type == ENCODING_ILLEGAL) {
  164.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEncodingIsIllegal,
  165.             "\n\rEncoding is illegal\n\r"), 0);
  166.     if (sleepmsg > 0)
  167.         sleep(sleepmsg);
  168.     return(-1);
  169.   }
  170.  
  171.   if (can_open(Expanded_Filename, "r")) {
  172.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmIncludeCannotAccess,
  173.             "\n\rInclude File can't be accessed\n\r"), 0);
  174.     if (sleepmsg > 0)
  175.         sleep(sleepmsg);
  176.     return(-1);
  177.   }
  178.   if (check) {
  179.     return(0);
  180.   }
  181.   if (Enc_Type == ENCODING_7BIT || Enc_Type == ENCODING_8BIT ||
  182.     Enc_Type == ENCODING_BINARY || Enc_Type == ENCODING_NONE ||
  183.     Enc_Type == ENCODING_EXPERIMENTAL) {
  184.     /* No explicit encoding, assume 7-BIT */
  185.     filename = Expanded_Filename;
  186.   } else {
  187.     sprintf(tmp_fn, "%semm.%d.%d", temp_dir, getpid(), getuid());
  188.     filename = tmp_fn;
  189.     if (Enc_Type == ENCODING_BASE64) {
  190.       strcpy(Encode_Flag, "-b");
  191.     } else if (Enc_Type == ENCODING_QUOTED) {
  192.       strcpy(Encode_Flag, "-q");
  193.     } else {
  194.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmUnknownEncodingInInclude,
  195.               "\n\rUnknown Encoding, include line ignored\n\r"), 0);
  196.       if (sleepmsg > 0)
  197.         sleep(sleepmsg);
  198.       return(-1);
  199.     }
  200.     sprintf(sh_buffer, "mmencode %s %s >%s", Encode_Flag, Expanded_Filename,
  201.             tmp_fn);
  202.     (void) system_call(sh_buffer, 0);
  203.   }
  204.   if ((incfile = fopen(filename, "r")) != NULL) {
  205.     if (stat(filename, &file_status) != 0) {
  206.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmCantStatIncludedFile,
  207.             "\n\rCan't stat included File,ignored\n\r"), 0);
  208.     if (sleepmsg > 0)
  209.         sleep(sleepmsg);
  210.     return(-1);
  211.     }
  212.     fprintf(dest, "%s %s\n", MIME_CONTENTTYPE, Content_Type);
  213.     fprintf(dest, "Content-Name: %s\n", Include_Filename);
  214.     fprintf(dest, "Content-Length: %d\n", file_status.st_size);
  215.     if (Enc_Type != ENCODING_NONE) {
  216.     fprintf(dest, "Content-Transfer-Encoding: %s\n", Encoding);
  217.     }
  218.     fprintf(dest, "\n");
  219.     while (line_len = fread(buffer, 1, sizeof(buffer), incfile)) {
  220.       if (fwrite(buffer, 1, line_len, dest) != line_len) {
  221.     MoveCursor(LINES, 0);
  222.     Raw(OFF);
  223.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmWriteFailedCopyAcross,
  224.             "\nWrite failed in copy_message_across\n"), 0);
  225.         emergency_exit();
  226.       }
  227.     } 
  228.  
  229. /*  write CRLF after body-part */
  230.  
  231.     fprintf(dest, "\n");
  232.  
  233.     fclose(incfile);
  234.     if (filename == tmp_fn) {
  235.     unlink(tmp_fn);
  236.     }
  237.   } else {
  238.     MoveCursor(LINES, 0);
  239.     Raw(OFF);
  240.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmCantOpenIncludedFile,
  241.             "\nCan't open included File\n"), 0);
  242.     emergency_exit();
  243.   }
  244.   return(0);
  245. }
  246.  
  247. int check_encoding(Encoding)
  248. char *Encoding;
  249. {
  250.     if (strlen(Encoding) == 0) return (ENCODING_NONE);
  251.     if (strincmp(Encoding, ENC_NAME_7BIT, strlen(ENC_NAME_7BIT)) == 0)
  252.         return (ENCODING_7BIT);
  253.     if (strincmp(Encoding, ENC_NAME_8BIT, strlen(ENC_NAME_8BIT)) == 0)
  254.         return (ENCODING_8BIT);
  255.     if (strincmp(Encoding, ENC_NAME_BINARY, strlen(ENC_NAME_BINARY)) == 0)
  256.         return (ENCODING_BINARY);
  257.     if (strincmp(Encoding, ENC_NAME_QUOTED, strlen(ENC_NAME_QUOTED)) == 0)
  258.         return (ENCODING_QUOTED);
  259.     if (strincmp(Encoding, ENC_NAME_BASE64, strlen(ENC_NAME_BASE64)) == 0)
  260.         return (ENCODING_BASE64);
  261.     if (strincmp(Encoding, "x-", 2) == 0) return (ENCODING_EXPERIMENTAL);
  262.     return(ENCODING_ILLEGAL);
  263. }
  264.  
  265. needs_mmdecode(s)
  266. char *s;
  267. {
  268.     char buf[SLEN];
  269.     char *t;
  270.     int EncType;
  271.  
  272.     if (!s) return(1);
  273.     while (*s && isspace(*s)) ++s;
  274.     t = buf;
  275.     while (*s && !isspace(*s) && ((t-buf) < SLEN)) *t++ = *s++;
  276.     EncType = check_encoding(buf);
  277.     if ((EncType == ENCODING_NONE) ||
  278.         (EncType == ENCODING_7BIT) ||
  279.         (EncType == ENCODING_8BIT) ||
  280.         (EncType == ENCODING_BINARY)) {
  281.         /* We don't need to go out to mmdecode, return 0 */
  282.         return(0);
  283.     } else {
  284.         return(1);
  285.     }
  286. }
  287.  
  288. notplain(s)
  289. char *s;
  290. {
  291.     char *t;
  292.     if (!s) return(1);
  293.     while (*s && isspace(*s)) ++s;
  294.     if (istrcmp(s, "text\n") == 0) {
  295.         /* old MIME spec, subtype now obligat, accept it as
  296.            "text/plain; charset=us-ascii" for compatibility
  297.            reason */
  298.         return(0);
  299.     }
  300.     if (strincmp(s, "text/plain", 10)) return(1);
  301.     t = (char *) index(s, ';');
  302.     while (t) {
  303.         ++t;
  304.         while (*t && isspace(*t)) ++t;
  305.         if (!strincmp(t, "charset", 7)) {
  306.             s = (char *) index(t, '=');
  307.             if (s) {
  308.                 ++s;
  309.                 while (*s && (isspace(*s) || *s == '\"')) ++s;
  310.                 if (!strincmp(s, display_charset, strlen(display_charset)))
  311.                     return(0);
  312.                 if (!strincmp(s, "us-ascii", 8)) {
  313.                     /* check if configured charset could
  314.                        display us-ascii */
  315.                     if(charset_ok(display_charset)) return(0);
  316.                 }
  317.             }
  318.             return(1);
  319.         }
  320.         t = (char *) index(t, ';');
  321.     }
  322.     return(0); /* no charset, was text/plain */
  323. }
  324.  
  325. int charset_ok(s)
  326. char *s;
  327. {
  328.     /* Return true if configured charset could display us-ascii too */
  329.     char buf[SLEN];    /* assumes sizeof(charset_compatlist) <= SLEN */
  330.     char *bp, *chset;
  331.  
  332.     /* the "charset_compatlist[]" format is: */
  333.     /*   charset charset charset ... */
  334.     bp = strcpy(buf, charset_compatlist);
  335.     while ((chset = strtok(bp, " \t\n")) != NULL) {
  336.     bp = NULL;
  337.     if (istrcmp(chset, s) == 0)
  338.         break;
  339.     }
  340.  
  341.     /* see if we reached the end of the list without a match */
  342.     if (chset == NULL) {
  343.     return(FALSE);
  344.     }
  345.     return(TRUE);
  346. }
  347. #endif /* MIME */
  348.